/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package client;
import Common.Message;
import java.net.*;
import java.io.*;

/**
 * For each ClientNetwork, a ClientThread is created 
 * to manage input datas from server.
 * 
 * @author hartingm
 */
public class ClientThread
			extends Thread{

	/********************
	 * Attributes
	 ********************/
	 private Socket transfertSocket;
	 private ProjetChatView projetChatView;
	 private ClientNetwork clientNetwork;
     private ConnectView connectView;
	 
	 //attributes used for send files
	 private boolean IsSendingFile;
	 private File fileToSend;
	 private String fileNickDest;

	 //attributes used to receive files
	 private boolean IsReceivingFile;
	 private String fileNickSrc;
	 private File newFile;
	 private FileOutputStream fileOut;

	/**
	 * Build a new ClientThread
	 *
	 * @param name the thread name
	 * @param clientNetwork the ClientNetwork wich created the thread
	 * @param projetChatView the ProjectChatView wich created the ClientNetwork
     * @param connectView the ConnectView that start the connection procedure
	 * @param tranfertSocket the socket created by ClientNetwork
	 */
	public ClientThread(String name, ClientNetwork clientNetwork, ProjetChatView projetChatView, ConnectView connectView, Socket tranfertSocket) {
		super(name);
		this.clientNetwork = clientNetwork;
		this.transfertSocket = tranfertSocket;
		this.projetChatView = projetChatView;
        this.connectView = connectView;
		
		this.IsSendingFile = false;
		this.fileToSend = null;
		this.fileNickDest = null;

		this.IsReceivingFile = false;
		this.newFile = null;
		this.fileOut = null;
		
		this.start();
	}

	/**
	 * The method executed by the thread.
	 */
	public void run() {
		for (;;) {
			Message message = readMessage();
			if (message != null)
				messageTreatment(message);
			else {
				System.out.println(this.getName()+": Error while receiving message.");

			}
		}
	}//end run

	/**
	 * Setter for IsSendingFile attribute.
	 * @param newValue the new value of IsSendingFile
	 */
	public void setIsSendingFile(boolean newValue) {
		this.IsSendingFile = newValue;
	}//end setIsSendingFile
	
	/**
	 * Setter for fileToSend attribute
	 * @param fileToSend the new value of fileToSend
	 */
	public void setFileToSend(File fileToSend) {
		this.fileToSend = fileToSend;
	}//end setFileToSend
	
	/**
	 * Setter for the fileNickDest attribute
	 *
	 * @param fileNickDest the recipient of file
	 */
	public void setNickDest(String fileNickDest) {
		this.fileNickDest = fileNickDest;
	}//end setNickDest

	/**
	 * Setter for the IsReceivingFile attribute
	 * @param newValue the new value of IsReceivingFile
	 */
	public void setIsReceivingFile(boolean newValue) {
		this.IsReceivingFile = newValue;
	}//end setIsReceivingFile

	/**
	 * Stop the client thread.
	 */
	public void stopClientThread() {
		System.out.println(this.getName()+": STOPPED.");
		this.stop();
	}//end stopClientThread

	/**
	 * Initialize the file transfert by setting all attributes needed
	 * to receive a file.
	 *
	 * @param newFile the new file already created
	 * @param fileNickSrc the source of file
	 */
	public void fileTransfertInit(File newFile, String fileNickSrc) {
		try{
			IsReceivingFile = true;
			this.newFile = newFile;
			this.fileNickSrc = fileNickSrc;
			fileOut = new FileOutputStream(newFile);
			System.out.println(this.getName()+": File tranfert initialized.");
		}
		catch (Exception e){
			System.out.println("Error while initializing file transfert.");
			IsReceivingFile = false;
			this.newFile = null;
			this.fileOut = null;
		}
	}//end fileTransfertInit

	/**
	 * Read a message from input data.
	 * @return the message received, null if an error has occured.
	 */
	 private Message readMessage() {
            try {
                InputStream inputStream = transfertSocket.getInputStream();
                DataInputStream dataInputStream = new DataInputStream(inputStream);

				byte[] messageByte = new byte[1024];
				String messageString;
				Message mess;
				
                byte type = dataInputStream.readByte();
                String nickSrc = dataInputStream.readUTF();
                String nickDest = dataInputStream.readUTF();

				//the message can be a byte[] or a string
				if (type == Message.FILE) {
					int lenght = dataInputStream.readInt();
					dataInputStream.read(messageByte);
					mess = new Message(type, nickSrc, nickDest, lenght, messageByte);
				}
				else {
					messageString = dataInputStream.readUTF();
					mess = new Message(type, nickSrc, nickDest, messageString);
				}

                projetChatView.setSendEnabled(true);

				System.out.println(this.getName() + ": Message received (type "+mess.getType()+").");
                return mess;
            }
            catch (Exception e){
				if (e instanceof EOFException) {
						System.out.println(this.getName()+": ERROR connection lost ("+e.toString()+").");
						
                        projetChatView.disconnection();
                        clientNetwork.disconnect(false);
					}
				else {
                        System.out.println(this.getName() + ": ERROR class ClientThread method readMessage"+e.toString());
                        projetChatView.disconnection();
                        clientNetwork.disconnect(false);
                }
                return null;
            }
	 }//end readMessage

	 /**
	  * Analyse the message and do the action associated by it's type.
	  * @param message the message to analyse.
	  */
	private void messageTreatment(Message message){

		switch(message.getType()) {
			//confirm connection
            case Message.CONNECTION_OK:
                connectView.connectionOk(clientNetwork);
                break;
				
			//diconnection message
			case Message.DISCONNECTION:
                connectView.connectionFailed();
                clientNetwork.disconnect(false);
				break;
				
			//message
			case Message.PRIVATE_MESSAGE:
				projetChatView.displayPersonnalMessage(message);
				break;

			//public message
			case Message.PUBLIC_MESSAGE:
				projetChatView.displayPublicMessage(message);
				break;

			//add client
			case Message.ADD_CLIENT:
				projetChatView.addClientToList(message.getNickSrc());
				break;

			//delete client
			case Message.DELETE_CLIENT:
				projetChatView.deleteClientFromList(message.getNickSrc());
				if (message.getNickSrc().equals(fileNickSrc)) { //if the client disconnected is the file sender then cancel receiving
					IsReceivingFile = false;
					fileNickSrc = null;
					System.out.println(this.getName()+": Delete new file. ");
					newFile.delete();
					newFile = null;
					fileOut = null;
					projetChatView.userMessage("File transfert failed", "The faile transfert failed beacause the sender is disconnected.");
					projetChatView.setProgressBarInderterminate(false);
					projetChatView.setProgressBarVisible(false);
					projetChatView.setStatus("Connected");
				}
				break;
				
			//file propose
			case Message.FILE_PROPOSE:
				projetChatView.messagePropose(message);
				break;
				
			//file accept
			case Message.FILE_ACCEPT:
				if (IsSendingFile) {
					projetChatView.setStatus("Sending file...");
					clientNetwork.sendFile(fileToSend, fileNickDest);
				} 
				else {
					System.out.println(this.getName()+": Message FILE_ACCEPT received but no FILE_PROPOSE sent -> Nothing to do.");
				}
				break;

			//file deny
			case Message.FILE_DENY:
				if (IsSendingFile) {
					projetChatView.setStatus("Connected.");
                    projetChatView.fileToSendDenied(fileNickDest);
					projetChatView.setProgressBarInderterminate(false);
					projetChatView.setProgressBarVisible(false);
					IsSendingFile = false;
                    fileToSend = null;
                    fileNickDest = null;
				}
				else {
					System.out.println(this.getName()+": Message FILE_ACCEPT received but no FILE_PROPOSE sent -> Nothing to do.");
				}
				break;

			//file
			case Message.FILE:
				if(IsReceivingFile) {
					if(fileNickSrc.equals(message.getNickSrc())) {
						try {
							fileOut.write(message.getMessageBytes(), 0, message.getLength());
							System.out.println(this.getName()+": New piece of file received.");
						}
						catch (Exception e) {
							System.out.println(this.getName()+": Error while receiving a piece of file ("+e.toString()+").");
						}
					}
					else
						System.out.println(this.getName() +": Message FILE received from an other sender -> Nothing to do.");
				}
				else
					System.out.println(this.getName()+": Message FILE received but no FILE_PROPOSE received -> Nothing to do.");
				break;

			//file end
			case Message.FILE_END:
				if (IsReceivingFile) {
					if(fileNickSrc.equals(message.getNickSrc())) {
						System.out.println(this.getName()+": File successfully received.");
                        projetChatView.userMessage("File received !", "The file transfer is finished. (You can find it in your home directory)");
						projetChatView.setStatus("Connected");
                        projetChatView.setProgressBarInderterminate(false);
                        projetChatView.setProgressBarVisible(false);
						IsReceivingFile = false;
						newFile = null;
						fileNickSrc = null;
						fileOut = null;
					}
					else
						System.out.println(this.getName()+": Message FILE_END received from an other sender -> Nothing to do.");
				}
				else
					System.out.println(this.getName()+": Message FILE_END received but no FILE_PROPOSE received -> Nothing to do.");
				break;

			//kick message
			case Message.KICK_MESSAGE:
				projetChatView.userMessage("Kicked !", "You have been kicked by " + message.getNickSrc() + " !");
				projetChatView.disconnection();
				clientNetwork.disconnect(false);
				break;

			//not recognized message type
			default:
				System.out.println(this.getName()+": Not recognized message type("+message.getType()+") -> ERROR.");
				break;
		}
	}//end messageTreatment
	
};//end ClientThread